<Info>
  Go hooks are currently available with the Odigos **Enterprise** plan.<br />
  [Contact us](https://odigos.io/) for more information.
</Info>

Odigos provides Go functions to augment and enhance auto-instrumentation. These functions are intended
to be used in conjunction with auto-instrumentation to provide enriched functionality and interaction for
developers running in an Odigos environment.

## Trace and Span Context

The following hooks allow you to access the current trace and span IDs in your application. 
This is useful when you need to correlate your application's logs with the distributed traces generated by Odigos.

These functions are available in the `github.com/odigos-io/odigos/hooks/go` module, ie:

```
go get github.com/odigos-io/odigos/hooks/go
```

### Get W3C Trace Context

```go
traceContext := gohooks.GetW3CTraceContext(context.Context) string
```
This function returns the full [W3C Trace Context](https://www.w3.org/TR/trace-context/) for the current function.

### Get Current Trace ID

```go
traceId := gohooks.GetTraceID(context.Context) string
```
Returns the current trace ID. If there is no active trace, it returns a zero value.

### Get Current Span ID

```go
spanId := gohooks.GetSpanID(context.Context) string
```
Returns the current span ID. If there is no active span, it returns a zero value.

### Check for zero values

The following helper functions can be used to check if the hooks returned a zero value. Zero
values indicate that no trace is currently active at the call site of the hook.

```go
isZeroTraceContext := gohooks.IsZeroTraceContext(traceContext)
isZeroTraceId := gohooks.IsZeroTraceId(traceId)
isZeroSpanId := gohooks.IsZeroSpanId(spanId)
```

## Gin Middleware

Odigos can instrument Gin middleware using a provided wrapper handler from `github.com/odigos-io/odigos/hooks/go/gin`:

```go
ginhooks.OdigosGinMiddleware(middlewares ...gin.HandlerFunc)
```

For example, see the following application that uses 2 middleware handlers, `LoggerMiddleware` and `AuthMiddleware`:

```go
package main

import (
	"log"
	"net/http"
	"time"

	"github.com/gin-gonic/gin"
	gohooks "github.com/odigos-io/odigos/hooks/go/gin"
)

func main() {
	r := gin.New()

	// Define all individual middleware
	middlewares := []gin.HandlerFunc{
		LoggerMiddleware(),
		AuthMiddleware(),
	}

	// Use the wrapper that chains the middleware
	r.Use(gohooks.OdigosGinMiddleware(middlewares...)...)

	// Sample route
	r.GET("/hello", func(c *gin.Context) {
		c.JSON(http.StatusOK, gin.H{"message": "Hello, world!"})
	})

	r.Run(":8080")
}

// LoggerMiddleware logs the request method, path, and duration.
func LoggerMiddleware() gin.HandlerFunc {
	return func(c *gin.Context) {
		start := time.Now()
		c.Next()
		log.Printf("Request: %s %s | Duration: %v", c.Request.Method, c.Request.URL.Path, time.Since(start))
	}
}

// AuthMiddleware checks for a static bearer token in the Authorization header.
func AuthMiddleware() gin.HandlerFunc {
	return func(c *gin.Context) {
		token := c.GetHeader("Authorization")
		if token != "Bearer secret-token" {
			c.JSON(http.StatusUnauthorized, gin.H{"error": "Unauthorized"})
			c.Abort()
			return
		}
		c.Next()
	}
}
```

The created spans will list the middleware function in the span attribute `odigos.gin.middleware.func`.
In the above example, these are `main.main.LoggerMiddleware.func2` and `main.main.AuthMiddleware.func3`.

## Example Application

First, follow the steps in the [Quickstart](/quickstart/introduction) to set up a Kind cluster,
install Jaeger, and [install Odigos](/quickstart/installation) (note: Go hooks are only available with
an enterprise token, which you can set in this walkthrough by installing with `--onprem-token=<YOUR_TOKEN>`).

Next create a folder for your sample app and initialize the Go module:

```bash
mkdir odigos-hooks-example && cd odigos-hooks-example
touch main.go
```

Now, here's a simple example using `net/http` that demonstrates how to use the Go hooks:

```go
package main

import (
  "fmt"
  "log"
  "net/http"

  gohooks "github.com/odigos-io/odigos/hooks/go"
)

func main() {
  // Create a simple HTTP server
  http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
    // Get the current trace and span IDs
    traceID := gohooks.GetTraceID(r.Context())
    spanID := gohooks.GetSpanID(r.Context())

    // Log the IDs
    log.Printf("Current Trace ID: %s", traceID)
    log.Printf("Current Span ID: %s", spanID)

    fmt.Fprintf(w, "Trace ID: %s\nSpan ID: %s\n", traceID, spanID)
	})

  // Start the server
  log.Println("Server starting on port 8080")
  if err := http.ListenAndServe(":8080", nil); err != nil {
    log.Fatalf("Failed to start server: %v", err)
  }
}
```

Initialize the Go module:

```bash
go mod init github.com/yourusername/odigos-hooks-example
go mod tidy
```

Create the following `Dockerfile`:

```dockerfile
# Build stage
FROM golang:1.24-alpine AS builder

WORKDIR /app

# Copy go mod and sum files
COPY go.mod go.sum ./

# Download dependencies
RUN go mod download

# Copy source code
COPY . .

# Build the application
RUN CGO_ENABLED=0 GOOS=linux go build -o hooks-example

# Final stage
FROM alpine:3.19

WORKDIR /app

# Copy the binary from builder
COPY --from=builder /app/hooks-example .

# Expose the application port
EXPOSE 8080

# Run the application
CMD ["./hooks-example"]
```

Build and push the image:

```bash
export IMAGE_TAG=docker.io/your-username/hooks-example
```

```bash
docker build -t $IMAGE_TAG .
docker push $IMAGE_TAG
```

Create the following `deployment.yaml`:

```yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: hooks-example
  labels:
    app: hooks-example
spec:
  replicas: 1
  selector:
    matchLabels:
      app: hooks-example
  template:
    metadata:
      labels:
        app: hooks-example
    spec:
      containers:
      - name: hooks-example
        image: ${IMAGE_TAG}
        ports:
        - containerPort: 8080
        resources:
          requests:
            cpu: "100m"
            memory: "128Mi"
          limits:
            cpu: "200m"
            memory: "256Mi"
---
apiVersion: v1
kind: Service
metadata:
  name: hooks-example
spec:
  selector:
    app: hooks-example
  ports:
  - port: 80
    targetPort: 8080
  type: ClusterIP
```

Apply the deployment using the `IMAGE_TAG` environment variable you defined above:

```bash
envsubst < deployment.yaml | kubectl apply -f -
```

Now, follow the Quickstart steps to [Build a pipeline](/quickstart/building-a-pipeline) in order to
instrument the sample application.

To generate traces, connect to the service with `kubectl port-forward`:

```bash
kubectl port-forward svc/hooks-example 8080:80
```

And in another terminal, generate spans with:

```bash
curl localhost:8080
```

And you will see the current trace and span ID returned:

```bash
$ curl localhost:8080
Trace ID: 1c3f5ea2cff194ba12d06b8353ae08ed
Span ID: 57460850f7634b30
```

Verify this is the same trace context shown in the Jaeger UI:

```bash
kubectl port-forward -n tracing svc/jaeger 16686:16686
```

And open `localhost:16686` in your browser.

## Troubleshooting

If you're not seeing trace or span IDs:

1. Make sure Odigos is properly configured and running
2. Verify that your application is being instrumented by Odigos
3. Check that you've initialized the hooks correctly
4. Ensure your application is receiving requests that are part of a trace
